define(function(require, exports, module) {

    var $ = window.Zepto;

    //     Zepto.js
    //     (c) 2010-2014 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.

    // The following code is heavily inspired by jQuery's $.fn.data()

    var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
        exp = $.expando = 'Zepto' + (+new Date()), emptyArray = [];

    // Get value from node:
    // 1. first try key as given,
    // 2. then try camelized key,
    // 3. fall back to reading "data-*" attribute.
    function getData(node, name) {
        var id = node[exp], store = id && data[id]
        if (name === undefined) return store || setData(node)
        else {
            if (store) {
                if (name in store) return store[name]
                var camelName = camelize(name)
                if (camelName in store) return store[camelName]
            }
            return dataAttr.call($(node), name)
        }
    }

    // Store value under camelized key on node
    function setData(node, name, value) {
        var id = node[exp] || (node[exp] = ++$.uuid),
            store = data[id] || (data[id] = attributeData(node))
        if (name !== undefined) store[camelize(name)] = value
        return store
    }

    // Read all "data-*" attributes from a node
    function attributeData(node) {
        var store = {}
        $.each(node.attributes || emptyArray, function(i, attr) {
            if (attr.name.indexOf('data-') == 0)
                store[camelize(attr.name.replace('data-', ''))] =
                    $.zepto.deserializeValue(attr.value)
        })
        return store
    }

    $.fn.data = function(name, value) {
        return value === undefined ?
            // set multiple values via object
            $.isPlainObject(name) ?
                this.each(function(i, node) {
                    $.each(name, function(key, value) {
                        setData(node, key, value)
                    })
                }) :
                // get value from first element
                (0 in this ? getData(this[0], name) : undefined) :
            // set value on all elements
            this.each(function() {
                setData(this, name, value)
            })
    }

    $.fn.removeData = function(names) {
        if (typeof names == 'string') names = names.split(/\s+/)
        return this.each(function() {
            var id = this[exp], store = id && data[id]
            if (store) $.each(names || store, function(key) {
                delete store[names ? camelize(this) : key]
            })
        })
    }

        // Generate extended `remove` and `empty` functions
    ;
    ['remove', 'empty'].forEach(function(methodName) {
        var origFn = $.fn[methodName]
        $.fn[methodName] = function() {
            var elements = this.find('*')
            if (methodName === 'remove') elements = elements.add(this)
            elements.removeData()
            return origFn.call(this)
        }
    })
});
